import { saveAs } from 'file-saver'
import { Workbook, Worksheet } from 'exceljs'

export async function download(name: string, columns: any[], data: any[], posted?: (sheet: Worksheet) => void) {
  const workbook = new Workbook()
  const sheet = workbook.addWorksheet(name)
  sheet.columns = columns.filter(c => c.dataIndex !== 'action').map(({ dataIndex, title, width, align }) => ({
    header: title,
    key: dataIndex,
    width: (width ?? 150) / 8,
    style: { alignment: { horizontal: align } },
  }))
  sheet.properties.outlineProperties = {
    summaryBelow: false,
    summaryRight: false,
  }

  fill(sheet, data)
  style(sheet)

  if (posted) {
    posted(sheet)
  }

  const buffer = await workbook.xlsx.writeBuffer()
  const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
  saveAs(blob, `${name}.xlsx`)
}

export async function upload(file: File, columns: any[]): Promise<any[]> {
  const buffer = await file.arrayBuffer()
  const workbook = new Workbook()
  await workbook.xlsx.load(buffer)

  const data: any[] = []
  const sheet = workbook.getWorksheet(1)

  if (sheet) {
    const headers = sheet.getRow(1).values as string[]
    const mapping = columns.filter(c => c.dataIndex !== 'action').reduce((map, { title, dataIndex }) => ({ ...map, [title]: dataIndex, }), {})
    const fields = headers.map(header => mapping[header])

    sheet.spliceRows(1, 1)

    sheet.eachRow(row => {
      const obj: any = {}
      row.eachCell(cell => {
        const col = Number.parseInt(cell.col)
        if (fields[col]) {
          const field = fields[col]
          obj[field] = cell.value
        }
      })
      data.push(obj)
    })
  }

  return data
}

function fill(sheet: Worksheet, data: any[], level = 0) {
  data.forEach(single => {
    const row = sheet.addRow(single)
    if (single.children) {
      fill(sheet, single.children, level + 1)
    }
    row.outlineLevel = level
  })
}

function style(sheet: Worksheet) {
  sheet.getRow(1).eachCell((cell) => {
    cell.font = { bold: true }
  })
  sheet.eachRow((row) => {
    if (row.outlineLevel && row.outlineLevel > 0) {
      row.hidden = true
      row.getCell(1).value = '  '.repeat(row.outlineLevel) + row.getCell(1).value
    }
    row.eachCell({ includeEmpty: true }, (cell) => {
      cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }
    })
  })
}
